#ifndef DSPSIMULATOR_DSPMACHINE_H
#define DSPSIMULATOR_DSPMACHINE_H

#include <memory>
#include <simulator/targetMachine/targetMachine.h>
#include <simulator/type/type.h>
#include <simulator/report/report.h>
#include <simulator/bitTools/bitTools.h>
#include <dspSimulator/targetMachine/addressMode.h>

class DspMachine : public TargetMachine {
private:
    // 用于保存当前所有的寄存器状态
    std::shared_ptr<RegisterMap> m_saveRegs;
public:
    DspMachine();

    ~DspMachine() override = default;

    /**
     * 用于实现读写分离，每次执行指令包之前，需要保存当前所有的寄存器状态
     */
    void updateSaveRegs() {
        m_saveRegs = std::make_shared<RegisterMap>(*m_regs);
    }

    std::shared_ptr<RegisterMap> getSaveRegs() { return m_saveRegs; }

    /**
     * 获取AMR寄存器表示的块大小，可选BK0 或 BK1
     * @param i BK的编号
     * @return
     */
    u32 getAMRBlockSize(u32 i) {
        std::bitset<32> AMRBits = *m_saveRegs->getReg32ByName("AMR")->getDataPtr();
        if (i > 1)
            fatalMacro("访问的BK不存在!");
        auto bkData = extractBits<5>(AMRBits, 16);
        if (i == 1)
            bkData = extractBits<5>(AMRBits, 21);
        return 1 << (bkData.to_ulong() + 1);
    }

    /**
     * 获取寄存器A的寻址模式
     * @param i 寄存器A的编号
     * @return
     */
    AddressingMode getRegAAddressingMode(u32 i) {
        std::bitset<32> AMRBits = *m_saveRegs->getReg32ByName("AMR")->getDataPtr();
        if (i == 4)
            return AddressingMode(extractBits<2>(AMRBits, 0).to_ulong());
        if (i == 5)
            return AddressingMode(extractBits<2>(AMRBits, 2).to_ulong());
        if (i == 6)
            return AddressingMode(extractBits<2>(AMRBits, 4).to_ulong());
        if (i == 7)
            return AddressingMode(extractBits<2>(AMRBits, 6).to_ulong());
        return AddressingMode::Linear;
    }

    /**
    * 获取寄存器B的寻址模式
    * @param i 寄存器B的编号
    * @return
    */
    AddressingMode getRegBAddressingMode(u32 i) {
        std::bitset<32> AMRBits = *m_saveRegs->getReg32ByName("AMR")->getDataPtr();
        if (i == 4)
            return AddressingMode(extractBits<2>(AMRBits, 8).to_ulong());
        if (i == 5)
            return AddressingMode(extractBits<2>(AMRBits, 10).to_ulong());
        if (i == 6)
            return AddressingMode(extractBits<2>(AMRBits, 12).to_ulong());
        if (i == 7)
            return AddressingMode(extractBits<2>(AMRBits, 14).to_ulong());
        return AddressingMode::Linear;
    }
};

#endif //DSPSIMULATOR_DSPMACHINE_H
